# 1. 什么是高阶函数和闭包并举例说明。
# 接收函数作为参数或者输出是一个函数的函数称为高阶函数
# 闭包指内层函数引用到外层函数的自由变量，形成闭包
# def counter():
#     a = 10
#     def inc(number):
#         r = a + number
#         return r
#     return inc
#
# f = counter()
#
# print(f(20))
# print(f(30))

# 2. 请列出functools包内的每个函数的功能作用。
# reduce:将函数结果作为参数迭代汇总
# from functools import reduce
# s = reduce(lambda x,y: x + y, range(10))
# print(s)
# # partial：偏函数，对一个函数的部分参数固定，返回一个包装函数
# from functools import partial
# def add(x, y=4):
#     return x + y
# newadd = partial(add, 4)
# print(newadd())
# lru_cache:将某个函数的参数和结果做映射并保存，方便后续输入相同参数时直接返回结果

# 3. 请使用已学习的装饰器相关知识自己实现functools.lru_cache。
from collections import defaultdict
from time import sleep
def mylru_cache(fn):
    argdict = defaultdict(str)
    def wrapper(*args, **kwargs):
        argkey = __makekey(*args, **kwargs)
        if argdict[argkey]:
            return argdict[argkey]
        else:
            ret = fn(*args, **kwargs)
            argdict[argkey] = ret
            return ret

    return wrapper

def __makekey(*args, **kwargs):
    positionarg = list(args)
    keywordarg = dict(kwargs)

    positionarglist = []
    for i,v in enumerate(positionarg):
        positionarglist.append(str(i) + ':' + str(v))

    keywordarglist = []
    for key,item in keywordarg.items():
        keywordarglist.append(str(key) + ':' + str(item))

    keywordarglist.sort(key=lambda x:x.split(':')[0])

    arglist = positionarglist + keywordarglist
    argkey = '_'.join(arglist)
    print(argkey)
    return argkey

@mylru_cache
def add(x, y=5):
    print('*'*30)
    sleep(3)
    return x + y

print(1, add(4, 5))
print(2, add(4, 5))
print(3, add(x=4, y=5))
print(4, add(y=5, x=4))
print(5, add(4.0, 5))
print(6, add(4))

# 4. 什么是类型注解并说明其背后的目的。
# 类型注解是对变量类型的说明，方便开发人员区分变量类型，无实际约束作用